package cn.kai.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.kai.base.BaseDO;
import cn.kai.base.BaseService;
import cn.kai.base.JsonResult;
import cn.kai.component.ProductExcelListener;
import cn.kai.dto.SysMenuTreeDto;
import cn.kai.dto.SysProductExcelDto;
import cn.kai.enums.ProductEnums;
import cn.kai.enums.SysMenuObjectTypeEnums;
import cn.kai.mapper.SysDataMapper;
import cn.kai.mapper.SysMenuMapper;
import cn.kai.mapper.SysMenuRelMapper;
import cn.kai.mapper.SysProductMapper;
import cn.kai.model.SysDataDO;
import cn.kai.model.SysMenuRelDO;
import cn.kai.model.SysProductDO;
import cn.kai.service.SysProductService;
import cn.kai.util.ConvertUtils;
import cn.kai.util.TreeUtil;
import cn.kai.vo.SysProductVO;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson2.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 产品表 服务实现类
 * </p>
 *
 * @author autoCode
 * @since 2025-03-08 05:14:07
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SysProductServiceImpl extends BaseService implements SysProductService {

    private final SysDataMapper sysDataMapper;
    private final SysProductMapper sysProductMapper;
    private final SysMenuMapper sysMenuMapper;
    private final SysMenuRelMapper sysMenuRelMapper;
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult uploadProductExcel(MultipartFile file) {
        try (InputStream inputStream = file.getInputStream()) {
            EasyExcel.read(inputStream, SysProductExcelDto.class,
                    ProductExcelListener.
                            builder()
                            .cacheList(new ArrayList<>())
                            .sysProductMapper(sysProductMapper)
                            .sysDataMapper(sysDataMapper)
                            .sysMenuMapper(sysMenuMapper)
                            .sysMenuRelMapper(sysMenuRelMapper)
                            .build()).sheet().doRead();
        } catch (Exception e) {
            log.error("e:", e);
        }
        return JsonResult.buildSuccess();
    }

    /**
     * 查询产品
     * @param name
     * @return
     */
    @Override
    public List<SysProductVO> queryProduct(String name) {
        return select(sysProductMapper)
                .where()
                .like(SysProductDO::getName, name)
                .list(SysProductVO.class);
    }

    @Override
    public SysProductVO getProductInfo(Long id) {
        SysProductDO sysProductDO = select(sysProductMapper).byId(id);
        if (Objects.isNull(sysProductDO)) {
            return null;
        }
        SysProductVO result = ConvertUtils.beanProcess(sysProductDO, SysProductVO.class);
        //根据产品类型获取信息
        ProductEnums productEnums = ProductEnums.valueOf(sysProductDO.getType());
        Map<String, JSONObject> info = new HashMap<>();
        switch (productEnums) {
            case C:
                //直接获取data
                List<SysDataDO> list = select(sysDataMapper)
                        .where()
                        .eq(SysDataDO::getObjectId, sysProductDO.getId())
                        .list();
                JSONObject data = new JSONObject();
                list.forEach(obj -> data.put(obj.getDataKey(), obj.getDataValue()));
                info.put(sysProductDO.getName(), data);
                break;
            default:
                processMenu(info,sysProductDO);
                break;
        }
        result.setInfo(info);
        return result;
    }

    private void processMenu(Map<String, JSONObject> info, SysProductDO sysProductDO) {
        //获取菜单树
        List<SysMenuRelDO> relList = select(sysMenuRelMapper)
                .cols(SysMenuRelDO::getMenuId)
                .where()
                .eq(SysMenuRelDO::getObjectId, sysProductDO.getId())
                .eq(SysMenuRelDO::getObjectType, SysMenuObjectTypeEnums.PRODUCT.name())
                .list();
        if (CollUtil.isEmpty(relList)) {
            return;
        }
        List<Long> menuIds = ConvertUtils.toFieldList(relList, SysMenuRelDO::getMenuId);
        //获取菜单信息
        List<SysMenuTreeDto> tree = select(sysMenuMapper)
                .where()
                .in(BaseDO::getId, menuIds)
                .list(SysMenuTreeDto.class);
        //转换为树
        List<SysMenuTreeDto> treeData = TreeUtil.buildTree(tree);
        //获取data
        Map<Long, JSONObject> dataMap = select(sysDataMapper)
                .where()
                .in(SysDataDO::getObjectId, menuIds)
                .list()
                .stream()
                .collect(Collectors.groupingBy(SysDataDO::getObjectId,
                        Collectors.collectingAndThen(Collectors.toList(), v -> {
                            JSONObject json = new JSONObject();
                            v.forEach(obj -> json.put(obj.getDataKey(), obj.getDataValue()));
                            return json;
                        })));
        //递归处理菜单数据
        processMenuData(treeData,dataMap,info,new StringBuilder());
    }

    private void processMenuData(List<SysMenuTreeDto> treeData, Map<Long, JSONObject> dataMap, Map<String, JSONObject> info, StringBuilder sb) {
        for (SysMenuTreeDto tree : treeData) {
            if (CollUtil.isNotEmpty(tree.getChildren())){
                sb.append(tree.getName());
                sb.append("-");
                processMenuData(tree.getChildren(),dataMap,info,sb);
            }else {
                sb.append(tree.getName());
                JSONObject jsonObject = dataMap.get(tree.getId());
                if (Objects.nonNull(jsonObject)){
                    //此操作主要为了让前端区分 菜单类型 如需要展示图片。但此字段前端不需要展示，所以需要前端特殊处理（删掉）。
                    if (StringUtils.isNotBlank(tree.getType())){
                        jsonObject.put("type",tree.getType());
                    }
                    info.put(sb.toString(),jsonObject);
                }
                sb.setLength(0);
            }
        }
    }
}
